package com.gxar.navigation.server.base.model.arithmetic.dto;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 地图
 *
 * @param <T> 节点
 */
public class Maps<T> {

    /**
     * 所有的节点集合
     * 节点Id - 节点
     */
    private final Map<T, Node<T>> nodes = new HashMap<>();

    /**
     * 地图构建器
     *
     * @param <T> 类型
     */
    public static class MapBuilder<T> {

        /**
         * map实例
         */
        private final Maps<T> map = new Maps<T>();

        /**
         * 构造MapBuilder
         *
         * @return MapBuilder
         */
        public MapBuilder<T> create() {
            return new MapBuilder<T>();
        }

        /**
         * 添加节点
         *
         * @param node 节点
         * @return 构建器
         */
        public MapBuilder<T> addNode(Node<T> node) {
            map.nodes.put(node.getId(), node);
            return this;
        }

        /**
         * 添加路线
         *
         * @param node1Id 节点Id
         * @param node2Id 节点Id
         * @param weight  权重
         * @return 构建器
         */
        public MapBuilder<T> addPath(T node1Id, T node2Id, long weight) {
            Node<T> node1 = map.nodes.get(node1Id);
            if (node1 == null) {
                throw new RuntimeException("无法找到节点:" + node1Id);
            }

            Node<T> node2 = map.nodes.get(node2Id);
            if (node2 == null) {
                throw new RuntimeException("无法找到节点:" + node2Id);
            }

            node1.getChild().put(node2, weight);
            node2.getChild().put(node1, weight);
            return this;
        }

        /**
         * 构建map
         *
         * @return map
         */
        public Maps<T> build() {
            return this.map;
        }

    }

    /**
     * 节点
     *
     * @param <T> 节点类型
     */
    public static class Node<T> {

        /**
         * 节点主键
         */
        private T id;

        /**
         * 节点联通路径
         * 相连节点 - 权重
         */
        private Map<Node<T>, Long> child = new HashMap<>();

        /**
         * 构造方法
         *
         * @param id 节点主键
         */
        public Node(T id) {
            this.id = id;
        }

        /**
         * 获取实例
         *
         * @param id 主键
         * @return 实例
         */
        public static <T> Node<T> valueOf(T id) {
            return new Node<T>(id);
        }

        /**
         * 是否有效
         * 用于动态变化节点的可用性
         *
         * @return 是否有效
         */
        public boolean validate() {
            return true;
        }

        /**
         * 节点ID
         *
         * @return id
         */
        public T getId() {
            return id;
        }

        /**
         * 设置id
         *
         * @param id id
         */
        public void setId(T id) {
            this.id = id;
        }

        /**
         * 获取子节点
         *
         * @return 子节点
         */
        public Map<Node<T>, Long> getChild() {
            return child;
        }

        /**
         * 设置子节点
         *
         * @param child 子节点
         */
        protected void setChild(Map<Node<T>, Long> child) {
            this.child = child;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append(this.id).append("[");
            for (Iterator<Entry<Node<T>, Long>> it = child.entrySet().iterator(); it.hasNext(); ) {
                Entry<Node<T>, Long> next = it.next();
                sb.append(next.getKey().getId()).append("=").append(next.getValue());
                if (it.hasNext()) {
                    sb.append(",");
                }
            }
            sb.append("]");
            return sb.toString();
        }

    }

    /**
     * 获取地图的无向图节点
     *
     * @return 节点Id - 节点
     */
    public Map<T, Node<T>> getNodes() {
        return nodes;
    }

}